<?php
/*
 * @Descripttion:
 * @version:
 * @Author: ewgof
 * @Date: 2020-09-19 23:11:21
 * @LastEditors: ewgof
 * @LastEditTime: 2020-12-04 16:12:15
 */
namespace cw;

use cw\interfaces\CacheInterface;

class FileCache extends Base implements CacheInterface
{
    protected $cache_prefix = '';  // 缓存键名前缀
    protected $filename = '';   // 缓存文件名
    protected $t = 0;
    protected $cache = [];      // 缓存数据
    protected $mtime = 0;       // 缓存文件上次修改时间（时间戳）

    public function __construct($name = null)
    {
        if (!empty(config('cache.prefix'))) {
            $this->cache_prefix = config('cache.prefix');
        } else {
            $this->cache_prefix = 'cw_cache:';
        }
        $path = rtrim(config('cache.path'), '/') . '/';
        if (!\file_exists($path)) {
            mkdir($path, 0755, true);
        }
        $this->filename = $path . make_sha($this->cache_prefix . $name) . '.cache';
        $this->t = time();
        $this->cache = $this->getArray();
        if (file_exists($this->filename)) {
            $this->mtime = filemtime($this->filename);
        } else {
            $this->mtime = $this->t;
        }
    }


    protected function getArray()
    {
        if (!file_exists($this->filename)) {
            return [];
        }
        $cache_data = json_decode(file_get_contents($this->filename), true);
        $cache_expire = $cache_data['expire'];
        if ($cache_expire != 0 && $this->mtime + $cache_expire <= $this->t) {
            // 如果缓存过期，删除缓存文件
            @unlink($this->filename);
            return [];
        }
        return $cache_data;
    }


    protected function writeDataToCacheFile()
    {
        $data_str = json_encode($this->cache);
        return file_put_contents($this->filename, $data_str);
    }



    public function get(String $name)
    {
        // $name = $this
        if (empty($name)) {
            return false;
        }
        if (isset($this->cache[$this->cache_prefix . $name])) {
            $val = $this->cache[$this->cache_prefix . $name];
        } else {
            $val = false;
        }
        return $val;
    }


    public function set(String $name, $val, $expire = null)
    {
        if (empty($name)) {
            return false;
        }
        if ($expire === null) {
            $expire = config('cache.expire');
        }
        $this->cache[$this->cache_prefix . $name] = $val;
        $this->cache['expire'] = $expire;
        return $this->writeDataToCacheFile();
    }

    /**
     * @name: inc
     * @msg: 缓存值自增
     * @param string $name 缓存键名
     * @param integer $step 自增步长，默认为1
     * @return boolean
     */
    public function inc(String $name, $step = 1)
    {
        if (empty($name)) {
            return false;
        }
        $expire = $this->cache['expire'];
        if ($expire == 0 || $expire + $this->mtime >= $this->t) {
            $val = $this->cache[$this->cache_prefix . $name];
            if (!\is_numeric($val)) {
                return false;
            }
            $this->cache[$this->cache_prefix . $name] = $val + $step;
            return $this->writeDataToCacheFile();
        } else {
            @unlink($this->filename);
            return false;
        }
    }


    /**
     * @name: dec
     * @msg: 缓存值自减
     * @param string $name 缓存键名
     * @param integer $step 自减步长，默认为1
     * @return boolean
     */
    public function dec(String $name, $step = 1)
    {
        if (empty($name)) {
            return false;
        }
        $expire = $this->cache['expire'];
        if ($expire == 0 || $expire + $this->mtime >= $this->t) {
            $val = $this->cache[$this->cache_prefix . $name];
            if (!\is_numeric($val)) {
                return false;
            }
            $this->cache[$this->cache_prefix . $name] = $val - $step;
            return $this->writeDataToCacheFile();
        } else {
            @unlink($this->filename);
            return false;
        }
    }

    /**
     * @name: delete
     * @msg: 删除缓存值
     * @param string $name 缓存键名
     * @return boolean
     */
    public function delete(String $name)
    {
        @unlink($this->filename);
        return true;
    }


    /**
     * @name: pull
     * @msg: 获取并删除缓存值
     * @param string $name 缓存键名
     * @return mixed
     */
    public function pull(String $name)
    {
        if (empty($name)) {
            return false;
        }

        $expire = $this->cache[$this->cache_prefix . $name];
        if ($expire == 0 || $expire + $this->mtime >= $this->t) {
            $val = $this->cache[$this->cache_prefix . $name];
        } else {
            $val = false;
        }
        @unlink($this->filename);
        return $val;
    }


    /**
     * @name: clean
     * @msg: 清除全部缓存值
     * @param boolean $delfile 清除缓存数据的同时是否删除文件
     * @return boolean
     */
    public function clean()
    {
        return (new cw\File)->rmovedir(config('cache.path'));
    }


    /**
     * @name: has
     * @msg: 判断缓存值是否存在
     * @param string $name 缓存键名
     * @return boolean
     */
    public function has(String $name)
    {
        if (empty($name)) {
            return false;
        }
        return isset($this->cache[$this->cache_prefix . $name]);
    }
}
